﻿package taurus.client.io;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.taurus.core.entity.ITObject;
import com.taurus.core.entity.TObject;
import com.taurus.core.util.StringUtil;

import taurus.client.Message;
import taurus.client.MessageResponse;
import taurus.client.NetManager;
import taurus.client.SocketCode;

/**
 * 协议处理控制器
 * 
 * @author daixiwei daixiwei15@126.com
 *
 */
public class SystemController {
	public static final String				CONNECT_TOKE				= "$t";
	public static final String				CONNECT_PROT_COMPRESSION	= "$pc";
	public static final String				REQUEST_CMD					= "$c";
	public static final String				REQUEST_GID					= "$gi";
	public static final String				REQUEST_PARM				= "$p";
	public static final String				REQUEST_RESULT				= "$r";

	/**
	 * pingpong
	 */
	public static final int					ACTION_PINGPONG				= 0;
	/**
	 * 客户端请求
	 */
	public static final int					ACTION_REQUST_CMD			= 1;
	/**
	 * 服务器事件消息
	 */
	public static final int					ACTION_EVENT_CMD			= 2;
	/**
	 * 验证客户端
	 */
	public static final int					ACTION_VALIDATE				= 3;

	private SocketEngine					_engine;
	private long							_lastTime;
	private List<Message>					_handleList					= new ArrayList<Message>();
	private int								_tempID;

	public SystemController(SocketEngine client) {
		_engine = client;
		_lastTime = System.currentTimeMillis();
	}

	private int _getValidID() {
		return ++_tempID;
	}


	public void handlePacket(Packet packet) {
		_lastTime = System.currentTimeMillis();
		switch (packet.actionID) {
		case ACTION_PINGPONG:
			fnPingPong(packet);
			break;
		case ACTION_REQUST_CMD:
			fnOperationResponse(packet);
			break;
		case ACTION_EVENT_CMD:
			fnOperationEvent(packet);
			break;
		case ACTION_VALIDATE:
			fnValidate(packet);
			break;
		}
	}

	void sendRequest(Message msg) throws IOException {
		Packet packet = new Packet();
		packet.actionID = SystemController.ACTION_REQUST_CMD;
		ITObject obj = TObject.newInstance();
		obj.putString(SystemController.REQUEST_CMD, msg.command);
		if (msg.useText && !StringUtil.isEmpty(msg.textParam))
        {
            try
            {
                obj.putTObject(REQUEST_PARM, TObject.newFromJsonData(msg.textParam));
            }
            catch(Exception e) { }
        }else
        {
            if (msg.param != null)
            {
                obj.putTObject(REQUEST_PARM, msg.param);
            }
        }
		int gid = 0;
		if (msg.callback != null) {
			gid = _getValidID();
			msg.lastTime = System.currentTimeMillis();
			msg.gid = gid;
			synchronized (_handleList) {
				_handleList.add(msg);
			}
		}
		obj.putInt(SystemController.REQUEST_GID, gid);
		packet.parameters = obj;
		_engine._packetHandler.onDataWrite(packet);
	}

	void sendPingPong() throws IOException {
		Packet packet = new Packet();
		packet.actionID = SystemController.ACTION_PINGPONG;
		packet.parameters = TObject.newInstance();
		_engine._packetHandler.onDataWrite(packet);
	}

	private final void fnOperationResponse(final Packet packet) {
		final int gid = packet.parameters.getInt(REQUEST_GID);
		final int result = packet.parameters.getInt(REQUEST_RESULT);
		ITObject tem = null;
		if (packet.parameters.containsKey(REQUEST_PARM)) {
			tem = packet.parameters.getTObject(REQUEST_PARM);
		}
		final ITObject param = tem;
		_engine.enqueueActionForDispatch(new Runnable() {
			@Override
			public void run() {
				handleOperationResponse(result, gid, param);
			}
		});
	}

	private void handleOperationResponse(int result, int gid, ITObject param) {
		Message msg = null;
		int index = 0;
		int len = _handleList.size();
		if (gid > 0) {
			for (int i = 0; i < len; ++i) {
				if (gid == _handleList.get(i).gid) {
					msg = _handleList.get(i);
					index = i;
					break;
				}
			}
		}

		if (msg != null) {
			if (msg.callback != null) {
				MessageResponse response = new MessageResponse();
				msg.param = param;
				response.messageData = msg;
				response.returnCode = result;
				msg.callback.action(response);
			}
			synchronized (_handleList) {
				_handleList.remove(index);
			}
		}
	}
	
	/**
	 * 验证合法客户端
	 * @param data
	 */
    void sendValidate(ITObject data) throws IOException{
        Packet packet = new Packet();
        packet.parameters = data;
        packet.actionID = ACTION_VALIDATE;
        _engine._packetHandler.onDataWrite(packet);
    }

	private final void fnOperationEvent(Packet packet) {
		final String cmd = packet.parameters.getString(REQUEST_CMD);
		ITObject tem = null;
		if (packet.parameters.containsKey(REQUEST_PARM)) {
			tem = packet.parameters.getTObject(REQUEST_PARM);
		}
		final ITObject param = tem;
		_engine.enqueueActionForDispatch(new Runnable() {
			@Override
			public void run() {
				handleEvent(cmd, param);
			}
		});
	}

	void handleEvent(String cmd, ITObject param) {
		Message msg = new Message();
		msg.command = cmd;
		msg.param = param;
		if (_engine._onEvent != null)
			_engine._onEvent.action(msg);
	}

	
	void fnValidate(Packet packet){
        ITObject param = packet.parameters;
        int code = param.getInt(REQUEST_RESULT);
        if(code == 0){
            _engine.sessionId = param.getInt(CONNECT_TOKE);
            _engine.protocolCompression = param.getInt(CONNECT_PROT_COMPRESSION);
            _engine.onValidate();
        }else{
            _engine.enqueueStatusCallback(SocketCode.Disconnect);
        }
    }
	
	private final void fnPingPong(Packet packet) {
		_engine._lagMonitor.fnPingPong();
	}

	public boolean isTimeOut() {
		return (System.currentTimeMillis() - _lastTime) / 1000 > NetManager.TIMEOUT_TIME;
	}

	public void refreshTime() {
		_lastTime = System.currentTimeMillis();
	}

}
